/**
 * Copyright (c) 2011 Nokia Corporation.
 */

#include "mygamewindow.h"

#include <QApplication>
#include <QDebug>
#include <math.h>


/*!
  \class MyGameWindow
  \brief Simple implementation of GE::GameWindow for playing couple of sounds
         and displaying an example effect with OpenGL ES 2.0.
*/


    // Vertex coordinates defining a plane with single trianglefan
const float plane_pos[12] = { -1.0f,-1.0f,0.0f, 1.0f,-1.0f,0.0f, 1.0f,1.0f,0.0f, -1.0f,1.0f,0.0f };

    // Vertex shader used by the example.
    // The uv - coordinates are calculated from the raw position of a vertex by scaling it between 0 and 1
const char *sample_vertex_shader_src = "\
    attribute highp vec3 vertex;\
    uniform mediump vec2 scale;\
    uniform mediump vec2 origo_pos;\
    varying mediump vec2 frag_uv;\
    void main(void)\
    {\
        gl_Position = (vec4(vertex,1) * vec4(scale.xy,1,1)) + vec4(origo_pos.xy,0,1);\
        frag_uv = vec2(vertex.x*0.5 + 0.5, vertex.y*-0.5 + 0.5);\
    }";

    // Fragment shader used by the example
const char *sample_fragment_shader_src = "\
    uniform mediump sampler2D sampler2d;\
    uniform mediump float mul;\
    varying mediump vec2 frag_uv;\
    void main(void)\
    {\
        gl_FragColor = texture2D(sampler2d, frag_uv)*mul;\
    }";



/*!
  Constructor.
  Just zero everything. The initialization is done later at onCreate
*/
MyGameWindow::MyGameWindow(QWidget *parent /* = 0 */)
    : GE::GameWindow(parent),
      hummSoundBuffer(0),
      clickSoundBuffer(0),
      leftPlayState(1.0f),
      rightPlayState(1.0f),
      radarAngle(0.0f),
      vertexShader(0),
      fragmentShader(0),
      shaderProgram(0),
      socketTexture(0),
      flareTexture(0),
      exitButtonTexture(0)
{
    for (int i = 0; i < NOF_LIGHTS; i++) {
        flarePower[i] = 0.0f;
    }
}


/*!
  Destructor.
*/
MyGameWindow::~MyGameWindow()
{

}


/*!
  From GameWindow
  \see gamewindow.cpp
*/
void MyGameWindow::onCreate()
{
        // Load the WAV-sounds from our resource file and store the content
    hummSoundBuffer = GE::AudioBuffer::loadWav(":/sounds/effect.wav");
    clickSoundBuffer = GE::AudioBuffer::loadWav(":/sounds/click.wav");

        // Set "destroywhenfinished"-flag to false for both of our playinstances.
        // This is required since we want to reuse same instances
        // constantly. By default, the playinstance is destroyed by
        // the mixer when it has finished playing.
    leftPlayInstance.setDestroyWhenFinished(false);
    rightPlayInstance.setDestroyWhenFinished(false);

        // Add our playinstances to the mixer's list of audio sources.
    getMixer().addAudioSource(&leftPlayInstance);
    getMixer().addAudioSource(&rightPlayInstance);
    getMixer().setGeneralVolume(0.4f);

        // Use a GE::GameWindow's helperfunction to create the shader from
        // the source strings. This could be done manually by using
        // glCreateShader, glShaderSource,glCompileShader, etc.
    if (glhelpCreateShader(
                vertexShader,
                fragmentShader,
                shaderProgram,
                sample_vertex_shader_src,
                sample_fragment_shader_src) == false)
    {
        // Failed to compile create shader
        qDebug() << "Failed to compile/link the shaderProgram";
    }

        // Put our freshly created shader to use
    glUseProgram(shaderProgram);

        // Load the textures, use a helper glhelpLoadTexture
        // which does the loading using QImage, generates corresponding
        // GLtexture and returns it's handle.
    socketTexture = glhelpLoadTexture(":/graphics/lightsocket.png");

    if (socketTexture == 0) {
        // Failed to load the socket texture
        qDebug() << "Failed to load socket texture";
    }

    flareTexture = glhelpLoadTexture(":/graphics/flare.png");

    if (flareTexture == 0) {
        // Failed to load the flare texture
        qDebug() << "Failed to load flare texture";
    }

    exitButtonTexture = glhelpLoadTexture(":/graphics/close_button.png");

    if (exitButtonTexture == 0) {
        // Failed to load the exit button texture
        qDebug() << "Failed to load exit button texture";
    }

        // Sets the sampler2D variable to the first texture unit
    glUniform1i(glGetUniformLocation(shaderProgram, "sampler2d"), 0);

    // Bind the attribute "vertex" of the shader into always at location 0
    glBindAttribLocation(shaderProgram, 0, "vertex");
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, plane_pos);

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_TEXTURE_2D);
    glDisable(GL_CULL_FACE);
    glDisable(GL_DEPTH_TEST);
    glDepthMask(GL_FALSE);

    glViewport(0,0, width(), height());
}


/*!
  From GameWindow
  \see gamewindow.cpp
*/
void MyGameWindow::onDestroy()
{
    getMixer().removeAudioSource(&leftPlayInstance);
    getMixer().removeAudioSource(&rightPlayInstance);

        // Destroy our soundbuffers releasing their resources.
    delete hummSoundBuffer;
    hummSoundBuffer = 0;
    delete clickSoundBuffer;
    clickSoundBuffer = 0;

        // And the shaderProgram
    glDeleteProgram(shaderProgram);

        // And the vertex- and fragment programs.
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

        // Delete the textures
    glDeleteTextures(1, &socketTexture);
    glDeleteTextures(1, &flareTexture);
    glDeleteTextures(1, &exitButtonTexture);
}


/*!
  From GameWindow
  \see gamewindow.cpp
*/
void MyGameWindow::onUpdate(const float frameDelta)
{
    float exRadarPos = sinf(radarAngle) * 2.0f;
    radarAngle += frameDelta * 3.0f; // 3.0f is a speed of the effect
    float radarPos = sinf(radarAngle) * 2.0f;

    for (int i = 0; i < NOF_LIGHTS; i++) {
            // Map the light's index between -1 and 1
        float lightpos = ((float)i / (NOF_LIGHTS - 1) - 0.5f) * 2.0f;

            // Calculate power for each light by using the distances cube
        float delta = (radarPos - lightpos) / 2.0f;
        delta = (1.0f - fabsf(delta));

        if (delta < 0.0f) {
            delta = 0.0f;
        }

        flarePower[i] = delta * delta;
    }

    leftPlayState += frameDelta;
    rightPlayState += frameDelta;

        // Control the sounds
    if (exRadarPos < -1.0f && radarPos >= -1.0f) {
        leftPlayInstance.playBuffer(hummSoundBuffer, 1.0f, 1.0f);
        leftPlayInstance.setRightVolume(0.0f);
        leftPlayState = 1.0f;
    }

    if (exRadarPos > 1.0 && radarPos <= 1.0f) {
        rightPlayInstance.playBuffer(hummSoundBuffer, 1.0f, 1.0f);
        rightPlayInstance.setLeftVolume(0.0f);
        rightPlayState = 1.0f;
    }

    leftPlayInstance.setSpeed(5.0f / (leftPlayState * 5.0f));
    leftPlayInstance.setLeftVolume(5.0f / (leftPlayState * 5.0f));

    rightPlayInstance.setSpeed(5.0f / (rightPlayState * 5.0f));
    rightPlayInstance.setRightVolume(5.0f / (rightPlayState * 5.0f));
}


/*!
  Overridden QWidget's virtual method which is called when user
  releases a pointer (mouse / finger) at the screen.
  This example uses it only to detect when close button is
  being pressed.
 */
void MyGameWindow::mouseReleaseEvent(QMouseEvent *e)
{
    if (e->x() > width() * 1/8 && e->y() < height() * 1/8) {
        qApp->exit(0);
    }
    else {
        // Manipulate light's position according event's Xposition
        float x = ((float)e->x() / (float)width()) - 0.5f;
        radarAngle = x * 3.14159f;
        clickSoundBuffer->playWithMixer(getMixer());
    }
}


/*!
  From GameWindow. Per frame rendering. You can use OpenGL ES 2.0 functionality
  freely here.
  \see gamewindow.cpp
*/
void MyGameWindow::onRender()
{
        // Clear the screen and depthbuffer
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glBindTexture(GL_TEXTURE_2D, socketTexture);

    float aspectRatio = (float)width() / (float)height();

        // Set the size scale according current aspectratio of the window
    glUniform2f(glGetUniformLocation(shaderProgram, "scale"), LIGHT_SIZE,
                LIGHT_SIZE * aspectRatio);
    glUniform1f(glGetUniformLocation(shaderProgram, "mul"), 1.0f);

        // Render the light sockets.
    for (int i = 0; i < NOF_LIGHTS; i++) {
        float yoffset = ((float)i - (float)(NOF_LIGHTS - 1) / 2.0f)
                / (NOF_LIGHTS * 2);
        glUniform2f(glGetUniformLocation(shaderProgram, "origo_pos"),
                    -LIGHT_STEP * ((float)NOF_LIGHTS - 1) / 2.0f + i * LIGHT_STEP,
                    -yoffset * yoffset * 3.0f);
        glDrawArrays(GL_TRIANGLE_FAN, 0,4);
    }

        // Render the light flares
    glBindTexture(GL_TEXTURE_2D, flareTexture);

    for (int i = 0; i < NOF_LIGHTS; i++) {
        float yoffset = ((float)i - (float)(NOF_LIGHTS - 1) / 2.0f)
                / (NOF_LIGHTS * 2);
        glUniform2f(glGetUniformLocation(shaderProgram, "origo_pos"),
                    -LIGHT_STEP * ((float)NOF_LIGHTS - 1) / 2.0f + i * LIGHT_STEP,
                    -yoffset * yoffset * 3.0f);

        float lightness = flarePower[i] * 1.2f;

        if (lightness > 1.0f) {
            lightness = 1.0f;
        }

        glUniform1f(glGetUniformLocation(shaderProgram, "mul"), lightness);

        float flareSize = flarePower[i] * 1.0f;
        glUniform2f(glGetUniformLocation(shaderProgram, "scale"), flareSize,
                    flareSize * aspectRatio);
        glDrawArrays(GL_TRIANGLE_FAN, 0,4);
    }

#ifndef MEEGO_EDITION_HARMATTAN
    // Render the close button
    glBindTexture(GL_TEXTURE_2D, exitButtonTexture);
    glUniform2f(glGetUniformLocation(shaderProgram, "scale"),
                EXIT_BUTTON_SIZE, EXIT_BUTTON_SIZE * aspectRatio);
    glUniform1f(glGetUniformLocation(shaderProgram, "mul"), 1.0f);
    glUniform2f(glGetUniformLocation(shaderProgram, "origo_pos"),
                (2.0f - EXIT_BUTTON_SIZE),
                (2.0f - EXIT_BUTTON_SIZE * aspectRatio));
    glDrawArrays(GL_TRIANGLE_FAN, 0,4);
#endif
}

